home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / WASTE 1.2 Distribution / WASTE 1.2 / WEHighLevelEditing.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-18  |  32.1 KB  |  1,357 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEHighLevelEditing.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  High-Level Editing Routines
  6.  *
  7.  *  Copyright (c) 1993-1996 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. typedef struct DoubleByte {
  18.     char firstByte;
  19.     char secondByte;
  20. } DoubleByte;
  21.  
  22. pascal void _WEPushAction(WEActionHandle hAction)
  23. {
  24.     WEPtr pWE = *((*hAction)->hOwner);
  25.     WEActionHandle hLast;
  26.  
  27.     // find the last action in the given stack
  28.     for ( hLast = hAction; (*hLast)->hNext != nil; hLast = (*hLast)->hNext )
  29.         ;
  30.  
  31.     // prepend hAction in front of the action stack
  32.     (*hLast)->hNext = pWE->hActionStack;
  33.     pWE->hActionStack = hAction;
  34. }
  35.  
  36. pascal OSErr _WENewAction(SInt32 rangeStart, SInt32 rangeEnd, SInt32 newTextLength,
  37.                             WEActionKind actionKind, WEActionFlags actionFlags,
  38.                             WEHandle hWE, WEActionHandle *hAction)
  39. {
  40.     WEActionPtr pAction;
  41.     OSErr err;
  42.  
  43.     // allocate a new action record
  44.     if ((err = _WEAllocate(sizeof(WEAction), kAllocClear, (Handle *)hAction)) != noErr)
  45.         goto cleanup1;
  46.  
  47.     // lock it down
  48.     HLock((Handle) *hAction);
  49.     pAction = **hAction;
  50.  
  51.     // fill in the fields
  52.     pAction->hOwner = hWE;
  53.     pAction->delRangeStart = rangeStart;
  54.     pAction->delRangeLength = newTextLength;
  55.     pAction->insRangeLength = rangeEnd - rangeStart;
  56.     pAction->actionKind = actionKind;
  57.     pAction->actionFlags = actionFlags;
  58.  
  59.     // remember selection range
  60.     WEGetSelection(&pAction->hiliteStart, &pAction->hiliteEnd, hWE);
  61.  
  62.     // allocate a handle to hold the text to be saved, unless otherwise specified
  63.     if ((actionFlags & weAFDontSaveText) == 0)
  64.     {
  65.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hText)) != noErr)
  66.             goto cleanup1;
  67.     }
  68.  
  69.     // allocate a handle to hold the styles to be saved, unless otherwise specified
  70.     if ((actionFlags & weAFDontSaveStyles) == 0)
  71.     {
  72.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hStyles)) != noErr)
  73.             goto cleanup1;
  74.     }
  75.  
  76. #if WASTE_OBJECTS
  77.     // allocate a handle to hold the "soup" to be saved, unless otherwise specified
  78.     if ((actionFlags & weAFDontSaveSoup) == 0)
  79.     {
  80.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hSoup)) != noErr)
  81.             goto cleanup1;
  82.     }
  83. #endif
  84.  
  85.     // make a copy of text range
  86.     if ((err = WECopyRange(rangeStart, rangeEnd, pAction->hText,
  87.             (Handle) pAction->hStyles, pAction->hSoup, hWE)) != noErr)
  88.         goto cleanup1;
  89.  
  90.     // unlock action record
  91.     HUnlock((Handle) *hAction);
  92.  
  93.     // skip clean-up section
  94.     goto cleanup0;
  95.  
  96. cleanup1:
  97.     // clean up
  98.     _WEForgetHandle(&pAction->hText);
  99.     _WEForgetHandle(&pAction->hStyles);
  100. #if WASTE_OBJECTS
  101.     _WEForgetHandle(&pAction->hSoup);
  102. #endif
  103.     _WEForgetHandle((Handle *)hAction);
  104.  
  105. cleanup0:
  106.     // return result code
  107.     return err;
  108.  
  109. }
  110.  
  111. pascal void _WEDisposeAction(WEActionHandle hAction)
  112. {
  113.     WEActionPtr pAction;
  114.     WEActionHandle hNext;
  115.  
  116.     for ( ; hAction != nil; hAction = hNext )
  117.     {
  118.         // lock the action record
  119.         HLock((Handle) hAction);
  120.         pAction = *hAction;
  121.         hNext = pAction->hNext;
  122.  
  123.         // throw away text, styles and soup
  124.         _WEForgetHandle(&pAction->hText);
  125.         _WEForgetHandle(&pAction->hStyles);
  126. #if WASTE_OBJECTS
  127.         _WEForgetHandle(&pAction->hSoup);
  128. #endif
  129.  
  130.         // throw away the action record itself
  131.         DisposeHandle((Handle) hAction);
  132.     }
  133. }
  134.  
  135. pascal void _WEForgetAction(WEActionHandle *hAction)
  136. {
  137.     WEActionHandle theAction;
  138.  
  139.     theAction = *hAction;
  140.     if (theAction != nil)
  141.     {
  142.         *hAction = nil;
  143.         _WEDisposeAction(theAction);
  144.     }
  145. }
  146.  
  147. pascal OSErr _WEDoAction(WEActionHandle hAction)
  148. {
  149.     WEActionHandle hRedoAction;
  150.     WEActionPtr pAction;
  151.     WEHandle hWE;
  152.     WEPtr pWE;
  153.     SInt32 offset, delOffset, insOffset;
  154.     SInt32 redrawStart, redrawEnd;
  155.     Boolean saveActionLock, saveWELock, saveTextLock;
  156.     OSErr err;
  157.  
  158.     // sanity check: make sure hAction isn't nil
  159.     if (hAction == nil)
  160.     {
  161.         return nilHandleErr;
  162.     }
  163.  
  164.     // get handle to associated WE instance
  165.     hWE = (*hAction)->hOwner;
  166.  
  167.     // lock the WE record
  168.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  169.     pWE = *hWE;
  170.  
  171.     // return an error code if this instance is read-only
  172.     err = weReadOnlyErr;
  173.     if (BTST(pWE->features, weFReadOnly))
  174.         goto cleanup;
  175.  
  176.     // stop any ongoing inline input session
  177.     WEStopInlineSession(hWE);
  178.  
  179.     // hide selection highlighting and the caret
  180.     _WEHiliteRange(pWE->selStart, pWE->selEnd, hWE);
  181.     if (BTST(pWE->flags, weFCaretVisible))
  182.         _WEBlinkCaret(hWE);
  183.  
  184.     redrawStart = LONG_MAX;
  185.     redrawEnd = 0;
  186.  
  187.     for ( ; hAction != nil; hAction = (*hAction)->hNext )
  188.     {
  189.         // lock the action record
  190.         saveActionLock = _WESetHandleLock((Handle) hAction, true);
  191.         pAction = *hAction;
  192.         offset = pAction->delRangeStart;
  193.         delOffset = offset + pAction->delRangeLength;
  194.         insOffset = offset + pAction->insRangeLength;
  195.  
  196.         // if undo support is enabled, save the range to be affected by this action
  197.         if (BTST(pWE->features, weFUndoSupport))
  198.         {
  199.             if (_WENewAction(offset, delOffset, pAction->insRangeLength, pAction->actionKind,
  200.                 (pAction->actionFlags ^ weAFIsRedo), hWE, &hRedoAction) == noErr)
  201.             {
  202.                 _WEPushAction(hRedoAction);
  203.             }
  204.         }
  205.  
  206.         if (pAction->hText != nil)
  207.         {
  208.             // delete the range to replace
  209.             if ((err = _WEDeleteRange(offset, delOffset, hWE)) != noErr)
  210.                 goto cleanup;
  211.  
  212.             // insert the saved text
  213.             saveTextLock = _WESetHandleLock(pAction->hText, true);
  214.             err = _WEInsertText(offset, *pAction->hText, pAction->insRangeLength, hWE);
  215.             _WESetHandleLock(pAction->hText, saveTextLock);
  216.             if (err != noErr)
  217.                 goto cleanup;
  218.         }
  219.  
  220.         // apply the saved styles, if any
  221.         if (pAction->hStyles != nil)
  222.         {
  223.             if ((err = _WEApplyStyleScrap(offset, insOffset, (StScrpHandle)pAction->hStyles, hWE)) != noErr)
  224.                 goto cleanup;
  225.         }
  226.  
  227. #if WASTE_OBJECTS
  228.         // the same goes for the soup
  229.         if (pAction->hSoup != nil)
  230.         {
  231.             if ((err = _WEApplySoup(offset, pAction->hSoup, hWE)) != noErr)
  232.                 goto cleanup;
  233.         }
  234. #endif
  235.  
  236.         // adjust redraw range
  237.         if (offset < redrawStart)
  238.             redrawStart = offset;
  239.         if (insOffset > redrawEnd)
  240.             redrawEnd = insOffset;
  241.  
  242.         // unlock action record
  243.         _WESetHandleLock((Handle) hAction, saveActionLock);
  244.  
  245.     } // for
  246.  
  247.     // restore the original selection range
  248.     pWE->selStart = pAction->hiliteStart;
  249.     pWE->selEnd = pAction->hiliteEnd;
  250.  
  251.     // redraw the text
  252.     if ((err = _WERedraw(redrawStart, redrawEnd, hWE)) != noErr)
  253.         goto cleanup;
  254.  
  255.     // clear result code
  256.     err = noErr;
  257.  
  258. cleanup:
  259.     // unlock the WE record
  260.     _WESetHandleLock((Handle) hWE, saveWELock);
  261.  
  262.     // return result code
  263.     return err;
  264. }
  265.  
  266. pascal OSErr WEUndo(WEHandle hWE)
  267. {
  268.     WEPtr pWE;
  269.     WEActionHandle hAction;
  270.     Boolean saveWELock;
  271.     OSErr err;
  272.  
  273.     // lock the WE record
  274.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  275.     pWE = *hWE;
  276.  
  277.     // "detach" the action stack from the WE instance
  278.     hAction = pWE->hActionStack;
  279.     pWE->hActionStack = nil;
  280.  
  281.     if (hAction != nil)
  282.     {
  283.  
  284.         // undoing a change _decrements_ the modification count;
  285.         // redoing the change increments it again
  286.         if (((*hAction)->actionFlags & weAFIsRedo) != 0)
  287.             pWE->modCount++;
  288.         else
  289.             pWE->modCount--;
  290.  
  291.         // perform the action...
  292.         err = _WEDoAction(hAction);
  293.  
  294.         // ...and throw it away
  295.         _WEDisposeAction(hAction);
  296.     }
  297.     else
  298.     {
  299.         // return an error code if the undo buffer is empty
  300.         err = weCantUndoErr;
  301.     }
  302.  
  303.     // unlock the WE record
  304.     _WESetHandleLock((Handle) hWE, saveWELock);
  305.  
  306.     return err;
  307. }
  308.  
  309. pascal void WEClearUndo(WEHandle hWE)
  310. {
  311.     // dispose of the action chain associated with the given WE instance
  312.     _WEForgetAction(&(*hWE)->hActionStack);
  313. }
  314.  
  315. pascal WEActionKind WEGetUndoInfo(Boolean *redoFlag, WEHandle hWE)
  316. {
  317.     WEActionHandle hAction;
  318.     WEActionKind theKind = weAKNone;
  319.     Boolean theFlag = false;
  320.  
  321.     if ((hAction = (*hWE)->hActionStack) != nil)
  322.     {
  323.         theKind = (*hAction)->actionKind;
  324.         theFlag = (((*hAction)->actionFlags & weAFIsRedo) != 0);
  325.     }
  326.  
  327.     if (redoFlag != nil)
  328.     {
  329.         *redoFlag = theFlag;
  330.     }
  331.     return theKind;
  332. }
  333.  
  334. pascal UInt32 WEGetModCount(WEHandle hWE)
  335. {
  336.     return (*hWE)->modCount;
  337. }
  338.  
  339. pascal void WEResetModCount(WEHandle hWE)
  340. {
  341.     (*hWE)->modCount = 0;
  342.     WEClearUndo(hWE);
  343. }
  344.  
  345. pascal void _WEAdjustUndoRange(SInt32 moreBytes, WEHandle hWE)
  346. {
  347.     WEActionHandle hAction;
  348.  
  349.     if ((hAction = (*hWE)->hActionStack) != nil)
  350.         (*hAction)->delRangeLength += moreBytes;
  351. }
  352.  
  353. pascal OSErr _WETypeChar(char theByte, WEHandle hWE)
  354. {
  355.     WEPtr pWE;
  356.     DoubleByte db;
  357.     SInt32 offset, endOffset, charLength;
  358.     OSErr err;
  359.  
  360.     pWE = *hWE;                    // the WE record must be already locked
  361.     charLength = 1;                // assume 1-byte character by default
  362.     db.firstByte = theByte;
  363.     offset = pWE->selStart;
  364.  
  365.     // delete current selection, if any
  366.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  367.         goto cleanup2;
  368.  
  369.     pWE->selEnd = offset; // needed in case we take a premature exit
  370.  
  371.     // make sure the font script is synchronized with the keyboard script
  372.     _WESynchNullStyle(hWE);
  373.  
  374.     if (BTST(pWE->flags, weFDoubleByte))
  375.     {
  376.  
  377.         // special processing for double-byte characters
  378.         if (pWE->firstByte != 0)
  379.         {
  380.  
  381.             // if this byte is the second half of a double-byte character,
  382.             // insert the two bytes at the same time (flush the double-byte cache)
  383.             db.firstByte = pWE->firstByte;
  384.             db.secondByte = theByte;
  385.             charLength = 2;
  386.             pWE->firstByte = 0;
  387.         }
  388.         else
  389.         {
  390.  
  391.             // if theByte is the first half of a double-byte character, just cache it and exit
  392.             if (CallWECharByteProc(&theByte, 0, FontToScript(pWE->nullStyle.runStyle.tsFont),
  393.                 hWE, pWE->charByteHook) == smFirstByte)
  394.             {
  395.                 pWE->firstByte = theByte;
  396.                 return noErr;
  397.             }
  398.         }
  399.  
  400.     } // if double-byte script installed
  401.  
  402.     // insert the new character into the text
  403.     if ((err = _WEInsertText(offset, (Ptr) &db, charLength, hWE)) != noErr)
  404.         goto cleanup2;
  405.  
  406.     // adjust undo buffer for the new character
  407.     _WEAdjustUndoRange(charLength, hWE);
  408.  
  409.     // invalid the null style
  410.     BCLR(pWE->flags, weFUseNullStyle);
  411.  
  412.     // move the insertion point after the new character
  413.     endOffset = offset + charLength;
  414.     pWE->selStart = endOffset;
  415.     pWE->selEnd = endOffset;
  416.  
  417.     // redraw the text
  418.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  419.         goto cleanup2;
  420.  
  421. cleanup1:
  422.     // clear result code
  423.     err = noErr;
  424.  
  425. cleanup2:
  426.     // return result code
  427.     return err;
  428.  
  429. }
  430.  
  431. pascal OSErr _WEBackspace(WEHandle hWE)
  432. {
  433.     // this routine is called by WEKey to handle the backspace key
  434.  
  435.     WEPtr pWE = *hWE;    // assume WE record is already locked
  436.     WEActionPtr pAction;
  437.     SInt32 rangeStart, rangeEnd, charLength;
  438.     WERunInfo runInfo;
  439.     DoubleByte db;
  440.     Boolean saveActionLock;
  441.     OSErr err;
  442.  
  443.     // calculate the text range to delete
  444.     // if the selection is non-empty, delete that
  445.     rangeStart = pWE->selStart;
  446.     rangeEnd = pWE->selEnd;
  447.     if (rangeStart == rangeEnd)
  448.     {
  449.  
  450.         // otherwise the selection is an insertion point
  451.         // do nothing if insertion point is at the beginning of the text
  452.         if (rangeStart == 0)
  453.             return noErr;
  454.  
  455.         // determine the byte-type of the character preceding the insertion point
  456.         charLength = (WECharByte(rangeStart - 1, hWE) == smSingleByte) ? 1 : 2;
  457.         rangeStart -= charLength;
  458.  
  459.         if (pWE->hActionStack != nil)
  460.         {
  461.             // UNDO SUPPORT FOR BACKSPACES
  462.  
  463.             // lock the action record
  464.             saveActionLock = _WESetHandleLock((Handle) pWE->hActionStack, true);
  465.             pAction = *pWE->hActionStack;
  466.  
  467.             // backspaces over the newly entered text aren't a problem
  468.             if (pAction->delRangeLength > 0)
  469.                 pAction->delRangeLength -= charLength;
  470.             else
  471.             {
  472.  
  473.                 // the hard part comes when backspacing past the new text because
  474.                 // the user is about to delete a character not included in the block we saved
  475.                 db.firstByte = WEGetChar(rangeStart, hWE);
  476.                 if (charLength == 2)
  477.                     db.secondByte = WEGetChar(rangeStart + 1, hWE);
  478.  
  479.                 // prepend the character to be deleted to the beginning of our saved text handle
  480.                 if ((err = _WEInsertBlock(pAction->hText, &db, charLength, 0)) != noErr)
  481.                     return err;
  482.  
  483.                 // adjust internal counters
  484.                 pAction->insRangeLength += charLength;
  485.                 pAction->delRangeStart -= charLength;
  486.  
  487.                 // get style run info associated with the about-to-be-deleted character
  488.                 WEGetRunInfo(rangeStart, &runInfo, hWE);
  489.  
  490.                 // prepend a new style element to our style scrap, if necessary
  491.                 if ((err = _WEPrependStyle(pAction->hStyles, &runInfo, charLength)) != noErr)
  492.                     return err;
  493.  
  494. #if WASTE_OBJECTS
  495.                 // do the same with our object "soup"
  496.                 if ((err = _WEPrependObject(pAction->hSoup, &runInfo, charLength)) != noErr)
  497.                     return err;
  498. #endif
  499.  
  500.             } // if deleting old text
  501.  
  502.             // unlock the action record
  503.             _WESetHandleLock((Handle) pWE->hActionStack, saveActionLock);
  504.  
  505.         } // if undo support is enabled
  506.     } // if selection is empty
  507.  
  508.     if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  509.         return err;
  510.  
  511.     // keep track of current selection range
  512.     pWE->selStart = rangeStart;
  513.     pWE->selEnd = rangeStart;
  514.  
  515.     // redraw the text
  516.     err = _WERedraw(rangeStart, rangeStart, hWE);
  517.  
  518.     return err;
  519. }
  520.  
  521. pascal OSErr _WEForwardDelete(WEHandle hWE)
  522. {
  523.  
  524.     // this routine is called by WEKey to handle the forward delete key
  525.  
  526.     WEPtr pWE = *hWE;    // assume WE record is already locked
  527.     WEActionPtr pAction;
  528.     SInt32 rangeStart, rangeEnd, charLength;
  529.     WERunInfo runInfo;
  530.     DoubleByte db;
  531.     Boolean saveActionLock;
  532.     OSErr err;
  533.  
  534.     // calculate the text range to delete
  535.     // if the selection is non-empty, delete that
  536.     rangeStart = pWE->selStart;
  537.     rangeEnd = pWE->selEnd;
  538.     if (rangeStart == rangeEnd)
  539.     {
  540.  
  541.         // otherwise the selection is an insertion point
  542.         // do nothing if insertion point is at the end of the text
  543.         if (rangeStart == pWE->textLength)
  544.             return noErr;
  545.  
  546.         // determine the byte-type of the character following the insertion point
  547.         charLength = (WECharByte(rangeStart, hWE) == smSingleByte) ? 1 : 2;
  548.         rangeEnd = rangeStart + charLength;
  549.  
  550.         if (pWE->hActionStack != nil)
  551.         {
  552.  
  553.             // UNDO SUPPORT FOR FORWARD DELETE
  554.  
  555.             // lock the action record
  556.             saveActionLock = _WESetHandleLock((Handle) pWE->hActionStack, true);
  557.             pAction = *pWE->hActionStack;
  558.  
  559.             // make a copy of the character about to be deleted
  560.             db.firstByte = WEGetChar(rangeStart, hWE);
  561.             if (charLength == 2)
  562.                 db.secondByte = WEGetChar(rangeStart + 1, hWE);
  563.  
  564.             // append it to the end of our saved text handle
  565.             PtrAndHand(&db, pAction->hText, charLength);
  566.             if ((err = MemError()) != noErr)
  567.                 return err;
  568.  
  569.             // get style run info associated with the about-to-be-deleted character
  570.             WEGetRunInfo(rangeStart, &runInfo, hWE);
  571.  
  572.             // append a new style element to our style scrap, if necessary
  573.             if ((err = _WEAppendStyle(pAction->hStyles, &runInfo, pAction->insRangeLength)) != noErr)
  574.                 return err;
  575.  
  576. #if WASTE_OBJECTS
  577.             // do the same with our object soup
  578.             if ((err = _WEAppendObject(pAction->hSoup, &runInfo, pAction->insRangeLength)) != noErr)
  579.                 return err;
  580. #endif
  581.  
  582.             // adjust internal counters
  583.             pAction->insRangeLength += charLength;
  584.  
  585.             // unlock the action record
  586.             _WESetHandleLock((Handle) pWE->hActionStack, saveActionLock);
  587.  
  588.         } // if undo support is enabled
  589.     } // if selection is empty
  590.  
  591.     if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  592.         return err;
  593.  
  594.     // keep track of current selection range
  595.     pWE->selStart = rangeStart;
  596.     pWE->selEnd = rangeStart;
  597.  
  598.     // redraw the text
  599.     err = _WERedraw(rangeStart, rangeStart, hWE);
  600.  
  601.     return err;
  602. }
  603.  
  604. pascal Boolean WEIsTyping(WEHandle hWE)
  605. {
  606.     // return true if we're tracking a typing sequence in the specified WE instance
  607.  
  608.     WEPtr pWE = *hWE;
  609.     WEActionPtr pAction;
  610.  
  611.     // there must be an undo buffer
  612.     if (pWE->hActionStack == nil)
  613.         return false;
  614.  
  615.     pAction = *pWE->hActionStack;
  616.  
  617.     // the action kind must be "typing" and the redo flag must be clear
  618.     if ((pAction->actionKind != weAKTyping) || ((pAction->actionFlags & weAFIsRedo) != 0))
  619.         return false;
  620.  
  621.     // finally, the selection range mustn't have moved since the last WEKey
  622.     if ((pWE->selStart != pWE->selEnd) ||
  623.         (pWE->selStart != pAction->delRangeStart + pAction->delRangeLength))
  624.         return false;
  625.  
  626.     return true;
  627. }
  628.  
  629. pascal void WEKey(SInt16 key, EventModifiers modifiers, WEHandle hWE)
  630. {
  631.     WEPtr pWE;
  632.     WEActionHandle hAction;
  633.     Boolean saveWELock;
  634.  
  635.     // lock the WE record
  636.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  637.     pWE = *hWE;
  638.  
  639.     // hide the caret if it's showing
  640.     if (BTST(pWE->flags, weFCaretVisible))
  641.         _WEBlinkCaret(hWE);
  642.  
  643.     // hide the cursor (it will show again as soon as it's moved)
  644.     ObscureCursor();
  645.  
  646.     // dispatch on key class (arrow keys, printable characters, backspace)
  647.     if ((key >= kArrowLeft) && (key <= kArrowDown))
  648.     {
  649.         _WEDoArrowKey(key, modifiers, hWE);
  650.     }
  651.     else
  652.     {
  653.  
  654.         // non-arrow keys modify the text, so make sure editing is allowed
  655.         if (!BTST(pWE->features, weFReadOnly))
  656.         {
  657.             // are we tracking a typing sequence?
  658.             if (!WEIsTyping(hWE))
  659.             {
  660.                 // nope;  start a new one
  661.                 // increment modification count
  662.                 pWE->modCount++;
  663.  
  664.                 // if undo support is enabled, create a new action to keep track of typing
  665.                 if (BTST(pWE->features, weFUndoSupport))
  666.                 {
  667.                     WEClearUndo(hWE);
  668.                     if (_WENewAction(pWE->selStart, pWE->selEnd, 0, weAKTyping, 0, hWE, &hAction) == noErr)
  669.                     {
  670.                         _WEPushAction(hAction);
  671.                     }
  672.                 }
  673.             } // if WEIsTyping
  674.  
  675.             if (key == kBackspace)
  676.             {
  677.                 _WEBackspace(hWE);
  678.             }
  679.             else if (key == kForwardDelete)
  680.             {
  681.                 _WEForwardDelete(hWE);
  682.             }
  683.             else
  684.             {
  685.                 _WETypeChar(key, hWE);
  686.             }
  687.         } // if not read-only
  688.     }
  689.  
  690.     // unlock the WE record
  691.     _WESetHandleLock((Handle) hWE, saveWELock);
  692. }
  693.  
  694. pascal OSErr WEInsert(Ptr textPtr, SInt32 textLength, StScrpHandle hStyles, Handle hSoup, WEHandle hWE)
  695. {
  696. #if !WASTE_OBJECTS
  697. #pragma unused(hSoup)
  698. #endif
  699.     WEPtr pWE;
  700.     SInt32 offset, endOffset;
  701.     WEActionHandle hAction;
  702.     SInt16 intPasteAction;
  703.     Boolean saveWELock;
  704.     char space = kSpace;
  705.     OSErr err;
  706.  
  707.     // lock the WE record
  708.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  709.     pWE = *hWE;
  710.     offset = pWE->selStart;
  711.  
  712.     // return an error code if this instance is read-only
  713.     err = weReadOnlyErr;
  714.     if (BTST(pWE->features, weFReadOnly))
  715.         goto cleanup;
  716.  
  717.     // stop any ongoing inline input session
  718.     WEStopInlineSession(hWE);
  719.  
  720.     // increment modification count
  721.     pWE->modCount++;
  722.  
  723.     // if undo support is enabled, save current selection range
  724.     if (BTST(pWE->features, weFUndoSupport))
  725.     {
  726.         WEClearUndo(hWE);
  727.         if (_WENewAction(offset, pWE->selEnd, textLength, weAKUnspecified, 0, hWE, &hAction) == noErr)
  728.         {
  729.             _WEPushAction(hAction);
  730.         }
  731.     }
  732.  
  733.     // delete current selection
  734.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  735.         goto cleanup;
  736.  
  737.     // insert the new text at the insertion point
  738.     if ((err = _WEInsertText(offset, textPtr, textLength, hWE)) != noErr)
  739.         goto cleanup;
  740.     endOffset = offset + textLength;
  741.  
  742.     if (hStyles != nil)
  743.     {
  744.  
  745.         // if a style scrap was supplied, apply it to the newly inserted text
  746.         if ((err = _WEApplyStyleScrap(offset, endOffset, hStyles, hWE)) != noErr)
  747.             goto cleanup;
  748.     }
  749.  
  750. #if WASTE_OBJECTS
  751.     if (hSoup != nil)
  752.     {
  753.         // if an object soup was supplied, apply it to the newly inserted text
  754.         if ((err = _WEApplySoup(offset, hSoup, hWE)) != noErr)
  755.             goto cleanup;
  756.     }
  757. #endif
  758.  
  759.     // determine whether an extra space should be added before or after the inserted text
  760.     intPasteAction = _WEIntelligentPaste(offset, endOffset, hWE);
  761.  
  762.     // add the extra space, if necessary
  763.     if (intPasteAction != weDontAddSpaces)
  764.     {
  765.         if (intPasteAction == weAddSpaceOnLeftSide)
  766.         {
  767.             err = _WEInsertText(offset, &space, sizeof(space), hWE);
  768.         }
  769.         else
  770.         {
  771.             err = _WEInsertText(endOffset, &space, sizeof(space), hWE);
  772.         }
  773.         if (err != noErr)
  774.             goto cleanup;
  775.         endOffset++;
  776.  
  777.         // adjust undo buffer (if any) for the extra space
  778.         _WEAdjustUndoRange(sizeof(space), hWE);
  779.     }
  780.  
  781.     // invalid the null style
  782.     BCLR(pWE->flags, weFUseNullStyle);
  783.  
  784.     // move the insertion point at the end of the inserted text
  785.     pWE->selStart = endOffset;
  786.     pWE->selEnd = endOffset;
  787.  
  788.     // redraw the text
  789.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  790.         goto cleanup;
  791.  
  792.     // clear result code
  793.     err = noErr;
  794.  
  795. cleanup:
  796.     // unlock the WE record
  797.     _WESetHandleLock((Handle) hWE, saveWELock);
  798.  
  799.     // return result code
  800.     return err;
  801. }
  802.  
  803. #if WASTE_OBJECTS
  804.  
  805. pascal OSErr WEInsertObject(FlavorType objectType, Handle objectDataHandle, Point objectSize, WEHandle hWE)
  806. {
  807.     WEPtr pWE;
  808.     WEActionHandle hAction;
  809.     SInt32 offset, endOffset;
  810.     WETextStyle ts;
  811.     Boolean saveWELock;
  812.     char marker = kObjectMarker;
  813.     OSErr err;
  814.  
  815.     BLOCK_CLR(ts);
  816.  
  817.     // lock the WE record
  818.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  819.     pWE = *hWE;
  820.     offset = pWE->selStart;
  821.  
  822.     // return an error code if this instance is read-only
  823.     err = weReadOnlyErr;
  824.     if (BTST(pWE->features, weFReadOnly))
  825.         goto cleanup;
  826.  
  827.     // stop any ongoing inline input session
  828.     WEStopInlineSession(hWE);
  829.  
  830.     // call the 'new' handler to initialize private object storage (if any)
  831.     // and to calculate the default size for this object
  832.  
  833.     if ((err = _WENewObject(objectType, objectDataHandle, hWE, &ts.tsObject)) != noErr)
  834.         goto cleanup;
  835.  
  836.     // use the specified object size, unless it is (0, 0), in which case keep the default size
  837.     if (* (SInt32 *) &objectSize != 0)
  838.     {
  839.         (*ts.tsObject)->objectSize = objectSize;
  840.     }
  841.  
  842.     // increment modification count
  843.     pWE->modCount++;
  844.  
  845.     // if undo support is enabled, save current selection range
  846.     if (BTST(pWE->features, weFUndoSupport))
  847.     {
  848.         WEClearUndo(hWE);
  849.         if (_WENewAction(offset, pWE->selEnd, 1, weAKUnspecified, 0, hWE, &hAction) == noErr)
  850.         {
  851.             _WEPushAction(hAction);
  852.         }
  853.     }
  854.  
  855.     // delete current selection
  856.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  857.         goto cleanup;
  858.  
  859.     // insert a kObjectMarker character at the insertion point
  860.     if ((err = _WEInsertText(offset, &marker, sizeof(marker), hWE)) != noErr)
  861.         goto cleanup;
  862.  
  863.     // move the insertion point after the inserted text
  864.     endOffset = offset + 1;
  865.     pWE->selStart = endOffset;
  866.     pWE->selEnd = endOffset;
  867.  
  868.     // record a reference to the object descriptor in the style table
  869.     err = _WESetStyleRange(offset, endOffset, weDoObject, &ts, hWE);
  870.     ts.tsObject = nil;
  871.     if (err != noErr)
  872.         goto cleanup;
  873.  
  874.     // invalid the null style
  875.     BCLR(pWE->flags, weFUseNullStyle);
  876.  
  877.     // redraw the text
  878.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  879.         goto cleanup;
  880.  
  881.     // clear result code
  882.     err = noErr;
  883.  
  884. cleanup:
  885.     // clean up
  886.     _WEForgetHandle((Handle *) &ts.tsObject);
  887.  
  888.     // unlock the WE record
  889.     _WESetHandleLock((Handle) hWE, saveWELock);
  890.  
  891.     // return result code
  892.     return err;
  893. }
  894.  
  895. #endif
  896.  
  897. pascal OSErr WEDelete(WEHandle hWE)
  898. {
  899.     WEPtr pWE;
  900.     WEActionHandle hAction;
  901.     SInt32 rangeStart, rangeEnd;
  902.     Boolean saveWELock;
  903.     OSErr err;
  904.  
  905.     // lock the WE record
  906.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  907.     pWE = *hWE;
  908.  
  909.     // return an error code if this instance is read-only
  910.     err = weReadOnlyErr;
  911.     if (BTST(pWE->features, weFReadOnly))
  912.         goto cleanup;
  913.  
  914.     // stop any ongoing inline input session
  915.     WEStopInlineSession(hWE);
  916.  
  917.     // get current selection range
  918.     rangeStart = pWE->selStart;
  919.     rangeEnd = pWE->selEnd;
  920.  
  921.     // do nothing if the selection range is empty
  922.     if (rangeStart < rangeEnd)
  923.     {
  924.  
  925.         // increment modification count
  926.         pWE->modCount++;
  927.  
  928.         // range extension for intelligent cut-and-paste
  929.         _WEIntelligentCut(&rangeStart, &rangeEnd, hWE);
  930.  
  931.         // if undo support is enabled, save the range to be deleted
  932.         if (BTST(pWE->features, weFUndoSupport))
  933.         {
  934.             WEClearUndo(hWE);
  935.             if (_WENewAction(rangeStart, rangeEnd, 0, weAKClear, 0, hWE, &hAction) == noErr)
  936.             {
  937.                 _WEPushAction(hAction);
  938.             }
  939.         }
  940.  
  941.         // delete the selection range
  942.         if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  943.             goto cleanup;
  944.  
  945.         // reset the selection range
  946.         pWE->selStart = rangeStart;
  947.         pWE->selEnd = rangeStart;
  948.  
  949.         // redraw the text
  950.         if ((err = _WERedraw(rangeStart, rangeStart, hWE)) != noErr)
  951.             goto cleanup;
  952.  
  953.     } // if non-empty selection
  954.  
  955.     // clear result code
  956.     err = noErr;
  957.  
  958. cleanup:
  959.     // unlock the WE record
  960.     _WESetHandleLock((Handle) hWE, saveWELock);
  961.  
  962.     // return result code
  963.     return err;
  964. }
  965.  
  966. pascal OSErr WECut(WEHandle hWE)
  967. {
  968.     OSErr err;
  969.  
  970.     // first copy...
  971.     if ((err = WECopy(hWE)) != noErr)
  972.         goto cleanup;
  973.  
  974.     // ... then delete
  975.     if ((err = WEDelete(hWE)) != noErr)
  976.         goto cleanup;
  977.  
  978.     // change the action kind of the most recent action, if any
  979.     if ((*hWE)->hActionStack != nil)
  980.     {
  981.         (*(*hWE)->hActionStack)->actionKind = weAKCut;
  982.     }
  983.  
  984. cleanup:
  985.     // return result code
  986.     return err;
  987. }
  988.  
  989. pascal Boolean WECanPaste(WEHandle hWE)
  990. {
  991.     SInt32 scrapOffset;
  992. #if WASTE_OBJECTS
  993.     FlavorType objectType;
  994.     SInt32 index;
  995. #endif
  996.  
  997.     if (!BTST((*hWE)->features, weFReadOnly))
  998.     {
  999.         // return true if the desk scrap contains a text flavor
  1000.         if (GetScrap(nil, kTypeText, &scrapOffset) > 0)
  1001.             return true;
  1002.  
  1003. #if WASTE_OBJECTS
  1004.         // see if the desk scrap contains a flavor matching one of the registered object types
  1005.         index = 0;
  1006.         while (_WEGetIndObjectType(index, &objectType, hWE) == noErr)
  1007.         {
  1008.             if (GetScrap(nil, objectType, &scrapOffset) > 0)
  1009.                 return true;
  1010.             index++;
  1011.         } // while
  1012. #endif
  1013.     } // if not read-only
  1014.     return false;
  1015. }
  1016.  
  1017. pascal OSErr WEPaste(WEHandle hWE)
  1018. {
  1019.     Handle hItem = nil;
  1020.     Handle hStyles = nil;
  1021.     Handle hSoup = nil;
  1022.     SInt32 scrapOffset;
  1023. #if WASTE_OBJECTS
  1024.     FlavorType objectType;
  1025.     SInt32 index;
  1026. #endif
  1027.     OSErr err;
  1028.  
  1029.     // allocate a handle to hold a scrap item
  1030.     if ((err = _WEAllocate(0, kAllocTemp, &hItem)) != noErr)
  1031.         goto cleanup;
  1032.  
  1033.     // look for a text flavor
  1034.     if (GetScrap(hItem, kTypeText, &scrapOffset) <= 0)
  1035.     {
  1036.  
  1037. #if WASTE_OBJECTS
  1038.         // no text: look for a flavor matching one of the registered object types
  1039.         index = 0;
  1040.         while (_WEGetIndObjectType(index, &objectType, hWE) == noErr)
  1041.         {
  1042.             if (GetScrap(hItem, objectType, &scrapOffset) > 0)
  1043.             {
  1044.                 Point objectSize;
  1045.                 * (SInt32 *) &objectSize = 0;
  1046.  
  1047.                 // found a registered type: create a new object out of the tagged data
  1048.                 err = WEInsertObject(objectType, hItem, objectSize, hWE);
  1049.  
  1050.                 // if successful, set hItem to nil so clean-up section won't kill the object data
  1051.                 if (err == noErr)
  1052.                     hItem = nil;
  1053.                 goto cleanup;
  1054.             }
  1055.  
  1056.             // try with next flavor
  1057.             index++;
  1058.         } // while
  1059. #endif
  1060.  
  1061.         // nothing pasteable: return an error code
  1062.         err = noTypeErr;
  1063.         goto cleanup;
  1064.     }
  1065.  
  1066.     if (!BTST((*hWE)->features, weFMonoStyled))
  1067.     {
  1068.         // allocate a handle to hold the style scrap, if any
  1069.         if ((err = _WEAllocate(0, kAllocTemp, &hStyles)) != noErr)
  1070.             goto cleanup;
  1071.  
  1072.         // look for a 'styl' item accompanying the text
  1073.         if (GetScrap(hStyles, kTypeStyles, &scrapOffset) <= 0)
  1074.             // forget the handle if nothing was found or an error occurred
  1075.             _WEForgetHandle(&hStyles);
  1076.  
  1077. #if WASTE_OBJECTS
  1078.         // allocate a handle to hold the soup, if any
  1079.         if ((err = _WEAllocate(0, kAllocTemp, &hSoup)) != noErr)
  1080.             goto cleanup;
  1081.  
  1082.         // look for a 'SOUP' item accompanying the text
  1083.         if (GetScrap(hSoup, kTypeSoup, &scrapOffset) <= 0)
  1084.             // forget the handle if nothing was found or an error occurred
  1085.             _WEForgetHandle(&hSoup);
  1086. #endif
  1087.     } // if not mono-styled
  1088.  
  1089.     // lock down the text
  1090.     HLock(hItem);
  1091.  
  1092.     // insert the text
  1093.     err = WEInsert(*hItem, GetHandleSize(hItem), (StScrpHandle) hStyles, hSoup, hWE);
  1094.  
  1095. cleanup:
  1096.     // if successful, change the action kind of the most recent action, if any
  1097.     if ((err == noErr) && ((*hWE)->hActionStack != nil))
  1098.     {
  1099.         (*(*hWE)->hActionStack)->actionKind = weAKPaste;
  1100.     }
  1101.  
  1102.     // clean up
  1103.     _WEForgetHandle(&hItem);
  1104.     _WEForgetHandle(&hStyles);
  1105. #if WASTE_OBJECTS
  1106.     _WEForgetHandle(&hSoup);
  1107. #endif
  1108.  
  1109.     // return result code
  1110.     return err;
  1111. }
  1112.  
  1113. pascal OSErr _WESmartSetFont(WEStyleMode mode, const TextStyle *ts, WEHandle hWE)
  1114. {
  1115.     WEPtr pWE = *hWE;    // assume WE record is already locked
  1116.     ScriptCode script;
  1117.     SInt32 runIndex;
  1118.     SInt32 rangeStart, rangeEnd;
  1119.     WERunInfo runInfo;
  1120.     GrafPtr savePort;
  1121.     SInt16 saveFont;
  1122.     OSErr err;
  1123.  
  1124.     // set up the graphics port
  1125.     GetPort(&savePort);
  1126.     SetPort(pWE->port);
  1127.     saveFont = pWE->port->txFont;
  1128.  
  1129.     // get the script corresponding to the font we're applying
  1130.     script = FontToScript(ts->tsFont);
  1131.  
  1132.     // walk through the style runs encompassing the selection range
  1133.     runIndex = _WEOffsetToRun(pWE->selStart, hWE);
  1134.     do {
  1135.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  1136.  
  1137.         if (pWE->selStart > runInfo.runStart)
  1138.             rangeStart = pWE->selStart;
  1139.         else
  1140.             rangeStart = runInfo.runStart;
  1141.  
  1142.         if (pWE->selEnd < runInfo.runEnd)
  1143.             rangeEnd = pWE->selEnd;
  1144.         else
  1145.             rangeEnd = runInfo.runEnd;
  1146.  
  1147.         // does this style run belong to the same script we're applying?
  1148.         if (FontToScript(runInfo.runAttrs.runStyle.tsFont) == script)
  1149.         {
  1150.             if ((err = _WESetStyleRange(rangeStart, rangeEnd, weDoFont, (WETextStyle *) ts, hWE)) != noErr)
  1151.                 goto cleanup;
  1152.             runIndex = _WEOffsetToRun(runInfo.runEnd, hWE);
  1153.         }
  1154.         else if ((mode & weDoExtractSubscript) != 0)
  1155.         {
  1156.             SInt32 runLength;
  1157.             SInt32 subrunLength;
  1158.             ScriptRunStatus runStatus;
  1159.  
  1160.             // FindScriptRun takes an implicit parameter through the txFont field of thePort
  1161.             TextFont(runInfo.runAttrs.runStyle.tsFont);
  1162.  
  1163.             runLength = rangeEnd - rangeStart;
  1164.             while (runLength > 0)
  1165.             {
  1166.                 // lock text handle
  1167.                 Boolean saveTextLock = _WESetHandleLock(pWE->hText, true);
  1168.  
  1169.                 // look for blocks of subscript text
  1170.                 runStatus = FindScriptRun(*pWE->hText + rangeStart, runLength, &subrunLength);
  1171.  
  1172.                 // unlock text handle
  1173.                 _WESetHandleLock(pWE->hText, saveTextLock);
  1174.  
  1175.                 if (runStatus.script == script)
  1176.                 {
  1177.                     // "extract" subscript text
  1178.                     if ((err = _WESetStyleRange(rangeStart, rangeStart + subrunLength, weDoFont, (WETextStyle *) ts, hWE)) != noErr)
  1179.                         goto cleanup;
  1180.                 }
  1181.                 rangeStart += subrunLength;
  1182.                 runLength -= subrunLength;
  1183.             }
  1184.             runIndex = _WEOffsetToRun(runInfo.runEnd, hWE);
  1185.         }
  1186.         else
  1187.             runIndex++;
  1188.  
  1189.     } while (runInfo.runEnd < pWE->selEnd);
  1190.  
  1191. cleanup:
  1192.     // restore the port
  1193.     TextFont(saveFont);
  1194.     SetPort(savePort);
  1195.  
  1196.     // return result code
  1197.     return err;
  1198. }
  1199.  
  1200. pascal OSErr WESetStyle(WEStyleMode mode, const TextStyle *ts, WEHandle hWE)
  1201. {
  1202.     WEPtr pWE;
  1203.     WEActionHandle hAction;
  1204.     ScriptCode fontScript;
  1205.     Boolean saveWELock;
  1206.     OSErr err;
  1207.  
  1208.     // lock the WE record
  1209.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1210.     pWE = *hWE;
  1211.  
  1212.     // return an error code if this instance is read-only
  1213.     err = weReadOnlyErr;
  1214.     if (BTST(pWE->features, weFReadOnly))
  1215.         goto cleanup;
  1216.  
  1217.     // stop any ongoing inline input session
  1218.     WEStopInlineSession(hWE);
  1219.  
  1220.     if (pWE->selStart == pWE->selEnd)
  1221.     {
  1222.  
  1223.         // NULL SELECTION
  1224.         // first make sure the nullStyle field contains valid information
  1225.         _WESynchNullStyle(hWE);
  1226.  
  1227.         // apply style changes to the nullStyle record
  1228.         _WECopyStyle((WETextStyle *) ts, &pWE->nullStyle.runStyle, pWE->nullStyle.runStyle.tsFace, mode);
  1229.  
  1230.         // special case: if this instance is empty, propagate the
  1231.         // change to the style table (this avoids some subtle problems)
  1232.         if (pWE->textLength == 0)
  1233.         {
  1234.             if ((err = _WESetStyleRange(0, 0, weDoAll + weDoReplaceFace, &pWE->nullStyle.runStyle, hWE)) != noErr)
  1235.                 goto cleanup;
  1236.         }
  1237.  
  1238.         // if the font was altered, synchronize the keyboard script
  1239.         if (BTST(pWE->flags, weFNonRoman) && (mode & weDoFont))
  1240.         {
  1241.             fontScript = FontToScript(pWE->nullStyle.runStyle.tsFont);
  1242.             if (fontScript != GetScriptManagerVariable(smKeyScript))
  1243.             {
  1244.                 KeyScript(fontScript);
  1245.             }
  1246.         }
  1247.     }
  1248.     else
  1249.     {
  1250.         // NON-EMPTY SELECTION
  1251.  
  1252.         // increment modification count
  1253.         pWE->modCount++;
  1254.  
  1255.         // if undo support is enabled, save the styles of the text range to be affected
  1256.         if (BTST(pWE->features, weFUndoSupport))
  1257.         {
  1258.             WEClearUndo(hWE);
  1259.             if (_WENewAction(pWE->selStart, pWE->selEnd, pWE->selEnd - pWE->selStart, weAKSetStyle,
  1260.                 weAFDontSaveText + weAFDontSaveSoup, hWE, &hAction) == noErr)
  1261.             {
  1262.                 _WEPushAction(hAction);
  1263.             }
  1264.         }
  1265.  
  1266.         // check for "smart" font modes
  1267.         if (BTST(pWE->flags, weFNonRoman) && ((mode & weDoSmartFont) == weDoSmartFont))
  1268.         {
  1269.             if ((err = _WESmartSetFont(mode, ts, hWE)) != noErr)
  1270.                 goto cleanup;
  1271.             mode &= ~weDoFont;
  1272.         }
  1273.  
  1274.         // set the style of the selection range
  1275.         if ((err = _WESetStyleRange(pWE->selStart, pWE->selEnd, mode, (WETextStyle *) ts, hWE)) != noErr)
  1276.             goto cleanup;
  1277.  
  1278.         // and redraw the text
  1279.         if ((err = _WERedraw(pWE->selStart, pWE->selEnd, hWE)) != noErr)
  1280.             goto cleanup;
  1281.     }
  1282.  
  1283.     // clear the result code
  1284.     err = noErr;
  1285.  
  1286. cleanup:
  1287.     // unlock the WE record
  1288.     _WESetHandleLock((Handle) hWE, saveWELock);
  1289.  
  1290.     // return result code
  1291.     return err;
  1292. }
  1293.  
  1294. pascal OSErr WEUseStyleScrap(StScrpHandle hStyles, WEHandle hWE)
  1295. {
  1296.     WEPtr pWE;
  1297.     Boolean saveWELock;
  1298.     OSErr err;
  1299.  
  1300.     // lock the WE record
  1301.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1302.     pWE = *hWE;
  1303.  
  1304.     // return an error code if this instance is read-only
  1305.     err = weReadOnlyErr;
  1306.     if (BTST(pWE->features, weFReadOnly))
  1307.         goto cleanup;
  1308.  
  1309.     // apply the style scrap to the selection range
  1310.     if ((err = _WEApplyStyleScrap(pWE->selStart, pWE->selEnd, hStyles, hWE)) != noErr)
  1311.         goto cleanup;
  1312.  
  1313.     // redraw the text
  1314.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  1315.  
  1316. cleanup:
  1317.     // unlock the WE record
  1318.     _WESetHandleLock((Handle) hWE, saveWELock);
  1319.  
  1320.     // return result code
  1321.     return err;
  1322. }
  1323.  
  1324. #if WASTE_OBJECTS
  1325.  
  1326. pascal OSErr WEUseSoup(Handle hSoup, WEHandle hWE)
  1327. {
  1328.     WEPtr pWE;
  1329.     Boolean saveWELock;
  1330.     OSErr err;
  1331.  
  1332.     // lock the WE record
  1333.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1334.     pWE = *hWE;
  1335.  
  1336.     // return an error code if this instance is read-only
  1337.     err = weReadOnlyErr;
  1338.     if (BTST(pWE->features, weFReadOnly))
  1339.         goto cleanup;
  1340.  
  1341.     // apply the soup starting from selStart
  1342.     if ((err = _WEApplySoup(pWE->selStart, hSoup, hWE)) != noErr)
  1343.         goto cleanup;
  1344.  
  1345.     // redraw the text
  1346.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  1347.  
  1348. cleanup:
  1349.     // unlock the WE record
  1350.     _WESetHandleLock((Handle) hWE, saveWELock);
  1351.  
  1352.     // return result code
  1353.     return err;
  1354. }
  1355.  
  1356. #endif  // WASTE_OBJECTS
  1357.